using System;
using System.Collections;
using System.Collections.Generic;
using LightCAD.MathLib;

namespace LightCAD.Three
{
    public class EllipseCurve : Curve<Vector2>
    {
        #region Properties

        public double aX;
        public double aY;
        public double xRadius;
        public double yRadius;
        public double aStartAngle;
        public double aEndAngle;
        public bool aClockwise;
        public double aRotation;

        #endregion

        #region constructor
        public EllipseCurve(double aX = 0, double aY = 0, double xRadius = 1, double yRadius = 1, double aStartAngle = 0, double aEndAngle = Math.PI * 2, bool aClockwise = false, double aRotation = 0)
        {
            this.type = "EllipseCurve";
            this.aX = aX;
            this.aY = aY;
            this.xRadius = xRadius;
            this.yRadius = yRadius;
            this.aStartAngle = aStartAngle;
            this.aEndAngle = aEndAngle;
            this.aClockwise = aClockwise;
            this.aRotation = aRotation;
        }
        #endregion

        #region methods
        public override Vector2 getPoint(double t, Vector2 optionalTarget = null)
        {
            var point = optionalTarget ?? new Vector2();
            var twoPi = MathEx.PI * 2;
            var deltaAngle = this.aEndAngle - this.aStartAngle;
            var samePoints = Math.Abs(deltaAngle) < MathEx.EPSILON;
            // ensures that deltaAngle is 0 .. 2 PI
            while (deltaAngle < 0) deltaAngle += twoPi;
            while (deltaAngle > twoPi) deltaAngle -= twoPi;
            if (deltaAngle < MathEx.EPSILON)
            {
                if (samePoints)
                {
                    deltaAngle = 0;
                }
                else
                {
                    deltaAngle = twoPi;
                }
            }
            if (this.aClockwise && !samePoints)
            {
                if (deltaAngle == twoPi)
                {
                    deltaAngle = -twoPi;
                }
                else
                {
                    deltaAngle = deltaAngle - twoPi;
                }
            }
            var angle = this.aStartAngle + t * deltaAngle;
            var x = this.aX + this.xRadius * Math.Cos(angle);
            var y = this.aY + this.yRadius * Math.Sin(angle);
            if (this.aRotation != 0)
            {
                var cos = Math.Cos(this.aRotation);
                var sin = Math.Sin(this.aRotation);
                var tx = x - this.aX;
                var ty = y - this.aY;
                // Rotate the point about the center of the ellipse.
                x = tx * cos - ty * sin + this.aX;
                y = tx * sin + ty * cos + this.aY;
            }
            return point.Set(x, y);
        }
        public override Curve<Vector2> copy(Curve<Vector2> source)
        {
            return copy(source as EllipseCurve);
        }
        public EllipseCurve copy(EllipseCurve source)
        {
            base.copy(source);
            this.aX = source.aX;
            this.aY = source.aY;
            this.xRadius = source.xRadius;
            this.yRadius = source.yRadius;
            this.aStartAngle = source.aStartAngle;
            this.aEndAngle = source.aEndAngle;
            this.aClockwise = source.aClockwise;
            this.aRotation = source.aRotation;
            return this;
        }

        public override Curve<Vector2> clone()
        {
            return new EllipseCurve().copy(this);
        }
        #endregion

    }
}
